package ufr_stgi.assistance_conduite;

import java.io.File;
import java.util.*;

import ufr_stgi.assistance_conduite.bdd.MaBaseSQLite;
import ufr_stgi.assistance_conduite.ecouteur.GPSListener;
import ufr_stgi.assistance_conduite.modele.ComparateurPanneauDistance;
import ufr_stgi.assistance_conduite.modele.Panneau;

import android.app.*;
import android.content.*;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationManager;
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;
import android.util.Log;

/**
 * Application qui contient les variables globales. elle est accessible dans toutes les activity par (MonApplication)getApplication().
 * Ce qui permet d'accéder dans n'importe quelle activity au modèle ((MonApplication)getApplication().getModele()) et à l'activity principale
 * @author Guillaume MONTAVON & Renaud DAVID (Master 2 RIM)
 */
public class MonApplication extends Application{
	
	private MainActivity Ma;
	private ReconnaissancePanneaux Rp;
	private Activity activityCourante;
	
	public static final int CODE_PREF_GPS = 1;
	public static final int CODE_ACTIVITY_AC = 2;
	public static final int CODE_ACTIVITY_RP = 3;
	public static final int CODE_PREFS_MENU = 4;
	public static final int CODE_ACTIVITY_LISTE_PANNEAUX = 5;
	
	public static final int CODE_NOTIFICATION_UPLOAD = 40;
	public static final int CODE_NOTIFICATION_SYNCHRO = 50;
	
	public static final double TAILLE_ZONE_POSITION = 0.2; //taille (en °) des zones de la Terre, le Smartphone téléchargera les panneaux se trouvant dans cette zone
	                                                       //à modifier seulement en modifiant aussi la taille des zone sur le serveur
	
	public static final int LISTE_PANNEAUX_NB_VISIBLE = 30; //nombre de panneaux visible dans l'activity ListePanneau
	
	public static final String PROXIMITY_INTENT_ACTION = new String("ufr_stgi.assistance_conduite.action.PROXIMITY_ALERT");
	public static final String PROXIMITY_ID_INTENT_EXTRA = "EventIDIntentExtraKey";
	public static final float PROXIMITY_RAYON_ALERT_METRE = 100f; //rayon en mètre autour de l'utilisateur dans lequel on doit signaler les panneaux
	public static final int PROXIMITY_EXPIRATION = 14400000; //date d'expiration du listener d'alerte des panneaux (4 heures)
	
	public static String adresseSeveur = "http://reconnaissance-panneaux.guillaume-montavon.fr/requete.php?objet="; //adresse du serveur distant
	
	private LocationManager locManager;
	private WifiManager lWifiManager;
	private TelephonyManager lTelephonyManager;
	private double latitude;
	private double longitude;
	private float vitesse; //vitesse en m/s
	private int direction; //0 : pas de direction car immobile, 1 : nord, 2 : est, 3 : sud, 4 : ouest
	private boolean enCoursSynchro; //true si on est train de synchroniser
	
	private MaBaseSQLite bdd; //base de données
	private GPSListener gps; //écouteur du GPS
	private long panneauPlusProche; //identifiant du panneau le plus proche de l'utilisateur
	
	private boolean premierLancement; //true si on vient de lancer l'application,
	//si on change l'orientation de l'application, l'activity redémarrera et elle sera à false
	
	private String dossierDest;
	
	private ArrayList<Panneau> listePanneauxProches;
	
	public MonApplication() {
		Ma = null;
		Rp = null;
		activityCourante = null;
		premierLancement = true;
		latitude = 0.0;
		longitude = 0.0;
		vitesse = 0;
		direction = 0;
		enCoursSynchro = false;
		listePanneauxProches = new ArrayList<Panneau>();
		gps = new GPSListener(this);
		panneauPlusProche = 0;
		
		dossierDest = "";
	}

	@Override
	public void onCreate() {
		super.onCreate();
		
		this.bdd = new MaBaseSQLite(this, "reconnaissance_panneaux.db", null, 1);
		
		locManager = (LocationManager)getSystemService(LOCATION_SERVICE);
		lWifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
		lTelephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
	}
	
	public void setLocManager(LocationManager locManager) {
		this.locManager = locManager;
	}
	
	public LocationManager getLocManager() {
		return locManager;
	}
	
	public Activity getActivityCourante() {
		return activityCourante;
	}
	
	public void setActivityCourante(Activity activityCourante) {
		this.activityCourante = activityCourante;
	}
	
	public GPSListener getGps() {
		return gps;
	}
	
	public double getLatitude() {
		return latitude;
	}
	
	public void setLatitude(double latitude) {
		this.latitude = latitude;
	}
	
	public double getLongitude() {
		return longitude;
	}
	
	public void setLongitude(double longitude) {
		this.longitude = longitude;
	}
	
	public float getVitesse() {
		return vitesse;
	}
	
	public void setVitesse(float vitesse) {
		this.vitesse = vitesse;
	}
	
	public int getDirection() {
		return direction;
	}
	
	public void setDirection(int direction) {
		this.direction = direction;
	}
	
	public long getPanneauPlusProche() {
		return panneauPlusProche;
	}

	public void setPanneauPlusProche(long panneauPlusProche) {
		this.panneauPlusProche = panneauPlusProche;
	}
	
	public boolean isEnCoursSynchro() {
		return enCoursSynchro;
	}
	
	public void setEnCoursSynchro(boolean enCoursSynchro) {
		this.enCoursSynchro = enCoursSynchro;
	}
	
	public String getDossierDest() {
		return dossierDest;
	}

	public void setDossierDest(String dossierDest) {
		this.dossierDest = dossierDest;
	}
	
	/**
	 * Ajoute un panneau qui est très proche de l'utilisateur
	 * @param p panneau à ajouter
	 */
	public void ajouterPanneauProche(Panneau p) {
		listePanneauxProches.add(p);
	}
	
	/**
	 * @return nombre de panneaux qui sont très proche de l'utilisateur (moins de 50m)
	 */
	public int nbPanneauxProches() {
		return listePanneauxProches.size();
	}
	
	/**
	 * Obtenir le panneau le plus proche et dans même direction que le Smartphone
	 * @return panneau le plus proche et dans même direction que le Smartphone
	 */
	public Panneau getPlusProchePanneau() {
		Panneau p = null;
		
		MAJListePanneauxProches();
		
		if(listePanneauxProches.size() > 0)
			p = listePanneauxProches.get(0);
		
		return p;
	}
	
	public void viderListePanneauxProches() {
		listePanneauxProches.clear();
	}
	
	/**
	 * Trie la liste des panneaux très proches du plus proche au plus éloigné, supprime les panneaux qui séloignent de la zone 
	 */
	public void MAJListePanneauxProches() {
		
		if(latitude != 0.0 && longitude != 0.0) {
			//calcul la distance entre l'utilisateur et le panneau
			for (int i = listePanneauxProches.size()-1; i >= 0; i--) {
				
				Location myLoc = new Location("");
				myLoc.setLatitude(latitude);
				myLoc.setLongitude(longitude);
				
				Location pLoc = new Location("");
				pLoc.setLatitude(listePanneauxProches.get(i).getLatitude());
				pLoc.setLongitude(listePanneauxProches.get(i).getLongitude());
				
				listePanneauxProches.get(i).setDistanceUtilisateur(Math.round(myLoc.distanceTo(pLoc)));
				
				//on supprime le panneau si il sort de notre zone
				if(listePanneauxProches.get(i).getDistanceUtilisateur() > PROXIMITY_RAYON_ALERT_METRE) {
					Log.i("supprime ListePanneauxProches", "distance : " + listePanneauxProches.get(i).getDistanceUtilisateur());
					listePanneauxProches.remove(i);
				}
			}
			
			Comparator<Panneau> compar = new ComparateurPanneauDistance();
			Collections.sort(listePanneauxProches,compar);
		}
		
	}
	
	public MaBaseSQLite getBdd() {
		return bdd;
	}
	
	/**
	 * Permet d'obtenir l'activity principale
	 * @return activity principale
	 */
	public MainActivity getMain() {
		return Ma;
	}
	
	public void setMain(MainActivity Ma) {
		this.Ma = Ma;
	}
	
	/**
	 * Permet d'obtenir l'activity reconnaissancePanneaux
	 * @return activity principale
	 */
	public ReconnaissancePanneaux getRp() {
		return Rp;
	}
	
	public void setRp(ReconnaissancePanneaux Rp) {
		this.Rp = Rp;
	}
	
	/**
	 * Permet d'obtenir la version de l'application qui se trouve dans le manifest
	 * @return version de l'application qui se trouve dans le manifest
	 */
	public int getVersionAppli() {
		
		int v = 0;
		try {
			v = getPackageManager().getPackageInfo(getApplicationInfo().packageName, 0).versionCode;
		} catch (NameNotFoundException e) {}
		
		return v;
	}
	
	/**
	 * Permet de connaître la dernière version lancée par l'utilisateur avant celle-ci
	 * @return dernière version lancée par l'utilisateur avant celle-ci
	 */
	public int getVersionPref() {
		
		return PreferenceManager.getDefaultSharedPreferences(Ma).getInt("version_appli", 0);
		
	}
	
	/**
	 * Permet de savoir si on lance une nouvelle version de l'application
	 * @return true si on lance une nouvelle version de l'application
	 */
	public boolean testNouvelleVersion() {
		
		if(getVersionAppli() > getVersionPref())
			return true;
		else
			return false;
		
	}
	
	/**
	 * Affiche un message de bienvenu ou des modification qui ont été apporté dans la nouvelle MAJ
	 */
	public void afficherMessageBienvenu() {
		
		if(testNouvelleVersion()) {
			enregistrerVersionAppliToPref();
			
			String[] listeNews = Ma.getResources().getStringArray(R.array.version_news);
			String message = "";
			if(getVersionAppli() == 1)
				message = listeNews[getVersionAppli()];
			else if(getVersionAppli() < listeNews.length)
				message = listeNews[1] + "\n" + listeNews[getVersionAppli()];
			else
				message = listeNews[0];
			
			AlertDialog.Builder builder = new AlertDialog.Builder(Ma);
			builder.setTitle(R.string.app_name);
			builder.setMessage(message);
			builder.setCancelable(false);
			builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {}
			});
			AlertDialog alert = builder.create();
			alert.show();
		
		}
	}
	
	/**
	 * Enregistre la version de l'application lancé comme étant la dernière lancée par l'utilisateur
	 */
	public void enregistrerVersionAppliToPref() {
		
		SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(Ma);
		Editor editor = preferences.edit();
		editor.putInt("version_appli", getVersionAppli());
		editor.commit();
		
	}
	
	/**
	 * Permet de savoir si on vient de lancer l'application
	 * @return true si on vient de lancer l'application
	 */
	public boolean isPremierLancement() {
		return premierLancement;
	}
	
	public void setPremierLancement(boolean premierLancement) {
		this.premierLancement = premierLancement;
	}
	
	
	/**
	 * Affiche une boite de dialogue demandant à l'utilisateur d'activer le GPS
	 */
	public void createGpsDisabledAlert() {
		if(activityCourante != null) {
			AlertDialog.Builder builder = new AlertDialog.Builder(activityCourante);  
			builder.setMessage(R.string.gps_message)
			.setCancelable(false)  
			.setPositiveButton(R.string.gps_actif, new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					showGpsOptions();  
				}
			})
			.setNegativeButton(R.string.gps_quitter, new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					try {
						Ma.finish();
					} catch (Exception e) {}
				}
			});
			AlertDialog alert = builder.create();  
			alert.show();
		}
	}
	
	
	/**
	 * Lance l'activity permettant d'activer le GPS
	 */
	public void showGpsOptions(){  
		Intent gpsOptionsIntent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);  
		activityCourante.startActivityForResult(gpsOptionsIntent, CODE_PREF_GPS);  
	}
	
	/**
	 * Teste la vitesse du réseau disponible sur le Smartphone
	 * @return true si une connexion Wifi ou 3G est disponible
	 */
	public boolean reseauRapide() {
		
		int type = lTelephonyManager.getNetworkType();
		
		// si on a une connexion rapide (Wifi ou 3g)
		if( (lWifiManager.isWifiEnabled() && lWifiManager.getConnectionInfo() != null && lWifiManager.getConnectionInfo().getIpAddress() != 0) || 
				((type == TelephonyManager.NETWORK_TYPE_UMTS || type == TelephonyManager.NETWORK_TYPE_HSDPA || type == TelephonyManager.NETWORK_TYPE_HSPA) 
				&& lTelephonyManager.getDataState() == TelephonyManager.DATA_CONNECTED) )
			return true;
		else
			return false;
		
	}
	
	/**
	 * Donne le répertoire contenant les images des panneaux
	 * @return dossier contenant les images des panneaux
	 */
	public File getDossierImage() {
		
		if(dossierDest.equals("")) {
			try {
				dossierDest = PreferenceManager.getDefaultSharedPreferences(this).getString("dir_carte_sd", "");
			} catch (Exception e) {}
			
			if(dossierDest.equals(""))
				dossierDest = "RecPan";	
		}
		
		File dossier = new File(Environment.getExternalStorageDirectory(), dossierDest);
		
		// Create the storage directory if it does not exist
		if (! dossier.exists()) {
			if (! dossier.mkdirs()) {
				Log.e("erreur", "impossible de créer le répertoire");
				dossier = null;
			}
		}
		
		return dossier;
	}
	
	/**
	 * Redimensionne une image
	 * @param image image à redimensionner
	 * @param largeur largeur de l'image souhaité
	 * @return image redimensionné (sous forme de Drawable)
	 */
	public Drawable redimensionnerImage(File image, int largeur) {
		
		Bitmap bitmap = null;
		try {
			bitmap = BitmapFactory.decodeFile(image.getAbsolutePath());
		} catch (Exception e) {}
		
		if(largeur != 0 && bitmap != null && bitmap.getWidth() != 0) {
			int hauteur = (int) Math.round(bitmap.getHeight() * (largeur * 1.0 / bitmap.getWidth()));

			return new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, largeur, hauteur, true));
		}
		else
			return null;
	}
	
}
